﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
enum DrawNavMeshFlags
{
    DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
    DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
    DU_DRAWNAVMESH_COLOR_TILES = 0x04,
};

public class HEAD_DATA
{
    public int datalen;
};

public class MESH_GROUP
{
    public int magic;
    public int version;
    public int meshCnt;
    public HEAD_DATA[] heads;
    public MESH_DATA[] meshs;
};

public class MESH_DATA
{
    public int magic;
    public int version;
    public Vector3[] vertexs;
    public int[] triangles;
    public Vector3 bmin;
    public Vector3 bmax;
};

[RequireComponent(typeof(RaceLogic))]
public class MapRenderForMesh : MonoBehaviour
{
    [DllImport("recast")]
    static extern void get_mesh_info(IntPtr ptr, ref int vcnt,ref int tcnt);
    [DllImport("recast")]
    static extern void get_mesh_vertexs(IntPtr ptr, long[] data, int length);
    [DllImport("recast")]
    static extern void get_mesh_triangles(IntPtr ptr, int[] data, int length);
    [DllImport("recast")]
    static extern void get_nav_mesh_graphics(IntPtr ptr,byte flags,long[] data, ref int dlen, uint[] colors,ref int clen);

    [DllImport("recast")]
    static extern void get_obstacle_graphics(IntPtr ptr, long[] data, ref int dlen, uint[] colors, ref int clen);

    /// <summary>
    /// 渲染控制数据
    /// </summary>
    [SerializeField]
    protected Material LineMat;
    [SerializeField]
    protected Color LineColor = new Color(1, 1, 1, 1);

    RaceLogic raceLogic;

    /// <summary>
    /// 原始几何绘制数据
    /// </summary>
    [SerializeField]
    [Tooltip("原始几何Y轴偏移")]
    protected float meshOffsetY = 0.0f;
    long[] verts;
    int[] tris;
    int vcnt;
    int tcnt;
    double l2d = 1.0 / 65536;

    /// <summary>
    /// 导航网格数据
    /// </summary>
    [SerializeField]
    [Tooltip("导航网格Y轴偏移")]
    protected float navMeshOffsetY = 0.0f;
    long[] nav_mesh_verts = new long[4096];
    int nav_mesh_length = 4096;
    uint[] colors = new uint[4096];
    int clen = 4096;
    byte flags = 0;
    [SerializeField]
    bool drawNavMeshClosedList = true;
    [SerializeField]
    bool drawNavMeshOffMeshCons = true;
    [SerializeField]
    bool drawNavMeshColorTiles = false;

    /// <summary>
    /// 动态阻挡数据
    /// </summary>
    long[] objstacle_verts = new long[256];
    int objstacle_vcnt = 256;
    uint[] objstacle_colors = new uint[128];
    int objstacle_ccnt = 128;
    [SerializeField]
    bool drawObstacles = true;
    bool obstacle_dirty = false;

    [SerializeField]
    TextAsset obj_mesh;
    [SerializeField]
    bool draw_export_mesh = true;
    [SerializeField]
    bool export_frame_mode = true;
    [SerializeField]
    Color m_frame_acolor = Color.white;
    [SerializeField]
    Color m_frame_bcolor = Color.white;
    [SerializeField]
    Color m_frame_ccolor = Color.white;

    static float cradio = 1.0f / 255.0f;
    static Color fourcc(uint c)
    {
        Color rc;
        rc.r = (c & 0xFF)* cradio;
        rc.g = ((c >> 8) & 0xFF) * cradio;
        rc.b = ((c >> 16) & 0xFF)* cradio;
        rc.a = ((c >> 24) & 0xFF)*cradio;
        return rc;
    }

    MESH_GROUP mesh_group = new MESH_GROUP();

    private void Awake()
    {
        raceLogic = GetComponent<RaceLogic>();
        if(null != obj_mesh)
        {
            using (MemoryStream ms = new MemoryStream(obj_mesh.bytes))
            {
                BinaryReader br = new BinaryReader(ms);
                mesh_group.magic = br.ReadInt32();
                mesh_group.version = br.ReadInt32();
                int mcnt = br.ReadInt32();
                mesh_group.meshCnt = mcnt;
                mesh_group.heads = new HEAD_DATA[mcnt];
                for (int i = 0; i < mcnt; ++i)
                {
                    mesh_group.heads[i] = new HEAD_DATA
                    {
                        datalen = br.ReadInt32()
                    };
                }
                mesh_group.meshs = new MESH_DATA[mcnt];
                Vector3 tv = Vector3.zero;
                for (int i = 0; i < mcnt; ++i)
                {
                    var mesh_data = new MESH_DATA();
                    mesh_group.meshs[i] = mesh_data;
                    mesh_data.magic = br.ReadInt32();
                    mesh_data.version = br.ReadInt32();
                    int vcnt = br.ReadInt32();
                    mesh_data.vertexs = new Vector3[vcnt];
                    for (int j = 0; j < vcnt; ++j)
                    {
                        mesh_data.vertexs[j] = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                    }
                    int tcnt = br.ReadInt16() * 3;
                    mesh_data.triangles = new int[tcnt];
                    var tris = mesh_group.meshs[i].triangles;
                    for (int j = 0; j < tcnt; j += 3)
                    {
                        tris[j] = br.ReadInt32();
                        tris[j + 1] = br.ReadInt32();
                        tris[j + 2] = br.ReadInt32();
                    }
                    mesh_group.meshs[i].bmin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                    mesh_group.meshs[i].bmax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                    UnityEngine.Debug.Log($"bmin={mesh_group.meshs[i].bmin} bmax={mesh_group.meshs[i].bmax}");
                }
                Debug.Assert(br.BaseStream.Position == obj_mesh.bytes.Length);
            }
        }
    }

    private void Update()
    {
        int targetFlags = 0;
        if (drawNavMeshOffMeshCons) targetFlags |= (int)DrawNavMeshFlags.DU_DRAWNAVMESH_OFFMESHCONS;
        if (drawNavMeshClosedList) targetFlags |= (int)DrawNavMeshFlags.DU_DRAWNAVMESH_CLOSEDLIST;
        if (drawNavMeshColorTiles) targetFlags |= (int)DrawNavMeshFlags.DU_DRAWNAVMESH_COLOR_TILES;
        if (((byte)targetFlags) != this.flags)
        {
            this.flags = ((byte)targetFlags);
            if(null != raceLogic)
                get_nav_mesh_graphics(raceLogic.Handle(), flags, nav_mesh_verts, ref nav_mesh_length, colors, ref clen);
        }
        if(obstacle_dirty)
        {
            obstacle_dirty = false;
            get_obstacle_graphics(raceLogic.Handle(), objstacle_verts, ref objstacle_vcnt, objstacle_colors, ref objstacle_ccnt);
        }
    }

    private void Start()
    {
        if(null != raceLogic && IntPtr.Zero != raceLogic.Handle())
        {
            get_mesh_info(raceLogic.Handle(), ref vcnt, ref tcnt);
            verts = new long[vcnt];
            tris = new int[tcnt];
            get_mesh_vertexs(raceLogic.Handle(), verts,vcnt);
            get_mesh_triangles(raceLogic.Handle(), tris,tcnt);
            obstacle_dirty = true;
        }
    }

    void drawV(long[] p,int idx,Color color,float yoffset = 0.0f)
    {
        GL.Color(color);
        float x = (float)(-p[idx] * l2d);
        float y = (float)(p[idx + 1] * l2d) + yoffset;
        float z = (float)(p[idx + 2] * l2d);
        GL.Vertex3(x,y,z);
    }

    private void OnRenderObject()
    {
        if (null != LineMat)
        {
            LineMat.SetColor("_Color", LineColor);
            LineMat.SetPass(0);
            GL.PushMatrix();
            //GL.wireframe = true;
            //GL.Begin(GL.TRIANGLES);
            //for (int i = 0; i < tcnt; i += 3)
            //{

            //    drawV(verts, tris[i] * 3, Color.blue, meshOffsetY);
            //    drawV(verts, tris[i + 2] * 3, Color.blue, meshOffsetY);
            //    drawV(verts, tris[i + 1] * 3, Color.blue, meshOffsetY);
            //}
            //GL.End();
            //GL.wireframe = false;
            //GL.Begin(GL.TRIANGLES);
            //for (int i = 0, j = 0; i < nav_mesh_length; i += 9, ++j)
            //{
            //    var c = fourcc(colors[j]);
            //    drawV(nav_mesh_verts, i, c, navMeshOffsetY);
            //    drawV(nav_mesh_verts, i + 6, c, navMeshOffsetY);
            //    drawV(nav_mesh_verts, i + 3, c, navMeshOffsetY);
            //}
            //GL.End();
            //GL.wireframe = false;
            //if (drawObstacles)
            //{
            //    GL.Begin(GL.TRIANGLES);
            //    for (int i = 0, j = 0; i < objstacle_vcnt; i += 9, ++j)
            //    {
            //        var c = fourcc(objstacle_colors[j]);
            //        drawV(objstacle_verts, i, c, 0);
            //        drawV(objstacle_verts, i + 6, c, 0);
            //        drawV(objstacle_verts, i + 3, c, 0);
            //    }
            //    GL.End();
            //}
            if(draw_export_mesh)
            {
                GL.wireframe = export_frame_mode;
                GL.Begin(GL.TRIANGLES);
                int n = mesh_group.meshs.Length;
                Vector3 t = Vector3.zero;
                for (int i = 0; i < n; ++i)
                {
                    var mesh = mesh_group.meshs[i];
                    for (int j = 0; j < mesh.triangles.Length; j += 3)
                    {
                        t = mesh.vertexs[mesh.triangles[j]];
                        GL.Color(m_frame_acolor);
                        GL.Vertex3(-t.x, t.y, t.z);
                        GL.Color(m_frame_bcolor);
                        t = mesh.vertexs[mesh.triangles[j + 2]];
                        GL.Vertex3(-t.x, t.y, t.z);
                        GL.Color(m_frame_ccolor);
                        t = mesh.vertexs[mesh.triangles[j + 1]];
                        GL.Vertex3(-t.x, t.y, t.z);
                    }
                }
                GL.End();
                GL.wireframe = false;
            }
            GL.PopMatrix();
        }
    }
}